home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 1 / LSD Compendium Deluxe 1.iso / a / programming / assemblers / cas.lha / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-14  |  20.4 KB  |  672 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <stdarg.h>
  6. #include "io.h"
  7. #include "op.h"
  8.  
  9. extern int Active;
  10.  
  11. /* SKIP LISTS are used to implement the symbol table */
  12.  
  13. char *CopyS(char *S) {
  14.    char *NewS;
  15.    if (S == 0) return 0;
  16.    NewS = Allocate(strlen(S) + 1);
  17.    strcpy(NewS, S);
  18.    return NewS;
  19. }
  20.  
  21. int CompS(char *A, char *B) {
  22.    if (A == 0) return (B == 0)? 0: +1;
  23.    if (B == 0) return -1;
  24.    for (; *A != '\0'; A++, B++) {
  25.       int Diff = tolower(*A) - tolower(*B);
  26.       if (Diff < 0) return -1;
  27.       if (Diff > 0) return +1;
  28.    }
  29.    return (*B == '\0')? 0: -1;
  30. }
  31.  
  32. static int Random(void) {
  33.    static byte B = 0, X = 0;
  34.    register int L = 0, D;
  35.    while (1) {
  36.       if (X == 0) X = 4, B = rand()&0xff;
  37.       D = B&3, B >>= 2, X--;
  38.       if (D) return L;
  39.       L++;
  40.    }
  41. }
  42.  
  43. #define MAX_BREADTH 16
  44. Symbol NIL;
  45. static Symbol Path[MAX_BREADTH];
  46. static int Breadth;
  47.  
  48. static Symbol Form(int B, char *Name) {
  49.    Symbol N = (Symbol)malloc(sizeof *N + B*sizeof(Symbol));
  50.    if (N == 0) fprintf(stderr, "Out of memory.\n"), exit(1);
  51.    N->Name = CopyS(Name),
  52.    N->Defined = N->Global = N->Variable = N->Address = N->Map = 0;
  53.    return N;
  54. }
  55.  
  56. #include <sys/types.h>
  57. /* #include <sys/timeb.h> */
  58.  
  59. void SymInit(void) {
  60. /*   struct timeb T;*/ int K;
  61. /*   ftime(&T); srand((unsigned int)(T.time ^ T.millitm)&0xffff);*/
  62.    NIL = Form(MAX_BREADTH - 1, 0);
  63.    for (K = 0; K < MAX_BREADTH; K++) NIL->Next[K] = NIL;
  64.    Breadth = 0;
  65. }
  66.  
  67. int Next, Value;
  68. int Line, StartLine;
  69.  
  70. Symbol LookUp(char *Name) {
  71.    int K/*, B*/; Symbol P, Q;
  72.    if (!Active) return 0;
  73.    for (K = Breadth, P = NIL; K >= 0; K--) {
  74.       Q = P->Next[K];
  75.       while (CompS(Q->Name, Name) < 0) P = Q, Q = Q->Next[K];
  76.       Path[K] = P;
  77.    }
  78.    if (CompS(Q->Name, Name) == 0) return Q;
  79.    K = Random(); if (K > Breadth) K = ++Breadth, Path[K] = NIL;
  80.    Q = Form(K, Name);
  81.    for (; K >= 0; K--) Q->Next[K] = Path[K]->Next[K], Path[K]->Next[K] = Q;
  82.    return Q;
  83. }
  84.  
  85. #define LINE_MAX 200
  86. char Text[LINE_MAX]; static char *U;
  87.  
  88. #define INCLUDE_MAX 5
  89. struct {
  90.    word Path; long Loc; int Next, Line;
  91. } IS[INCLUDE_MAX], *ISP;
  92. static FILE *InF; 
  93. extern FILE *OutF; /* 'extern' by caro - see link.c */
  94. char **FileTab; long Files;
  95. int StartF, CurF;
  96. static int FileMax;
  97.  
  98. void FileInit(void) {
  99.    ISP = IS - 1, FileTab = 0, Files = 0, FileMax = 0;
  100. }
  101.  
  102. static byte ERRORS = 0;
  103. char InSeg = 0;
  104. void ERROR(const char *Format, ...) {
  105.    va_list AP;
  106.    if (InSeg) printf("%s: [%d] ", FileTab[StartF], StartLine);
  107.    va_start(AP, Format);
  108.    vprintf(Format, AP); putchar('\n');
  109.    va_end(AP);
  110.    if (++ERRORS >= 24) printf("Too many errors.  Aborting.\n"), exit(1);
  111.  
  112. void FATAL(const char *Format, ...) {
  113.    va_list AP;
  114.    if (InSeg) printf("%s: [%d] ", FileTab[StartF], StartLine);
  115.    va_start(AP, Format);
  116.    vprintf(Format, AP); putchar('\n');
  117.    va_end(AP);
  118.    exit(1);
  119. }
  120.  
  121. void CHECK(void) {
  122.    if (ERRORS > 0) printf("Errors present.  Assembly stopped.\n"), exit(1);
  123. }
  124.  
  125. byte GetB(FILE *FP) {
  126.    int A;
  127.    A = fgetc(FP); if (A == EOF) FATAL("Unexpected EOF.");
  128.    return ((byte)(A&0xff));
  129. }
  130.  
  131. word GetW(FILE *FP) {
  132.    int A, B;
  133.    A = fgetc(FP); if (A == EOF) FATAL("Unexpected EOF.");
  134.    B = fgetc(FP); if (B == EOF) FATAL("Unexpected EOF.");
  135.    return ((word)((A&0xff) << 8 | B&0xff));
  136. }
  137.  
  138. unsigned long GetL(FILE *FP) {
  139.    int A, B, C, D;
  140.    A = fgetc(FP); if (A == EOF) FATAL("Unexpected EOF.");
  141.    B = fgetc(FP); if (B == EOF) FATAL("Unexpected EOF.");
  142.    C = fgetc(FP); if (C == EOF) FATAL("Unexpected EOF.");
  143.    D = fgetc(FP); if (D == EOF) FATAL("Unexpected EOF.");
  144.    return ((unsigned long)((A&0xff) << 24 | (B&0xff) << 16 | (C&0xff) << 8 | D&0xff));
  145. }
  146.  
  147. void PutB(byte B, FILE *FP) { fputc(B, FP); }
  148.  
  149. void PutW(word W, FILE *FP) {
  150.    char A = (W >> 8)&0xff, B = W&0xff;
  151.    fputc(A, FP), fputc(B, FP);
  152. }
  153.  
  154. void PutL(unsigned long L, FILE *FP) {
  155.    char A = (L >> 24)&0xff, B = (L >> 16)&0xff, C = (L >> 8)&0xff, D = L&0xff;
  156.    fputc(A, FP), fputc(B, FP), fputc(C, FP), fputc(D, FP);
  157. }
  158.  
  159. void *Allocate(unsigned Size) {
  160.    void *X;
  161.    if (Size == 0) return 0;
  162.    X = malloc(Size); if (X == 0) FATAL("Out of memory.");
  163.    return X;
  164. }
  165.  
  166. void OpenF(char *Name) {
  167.    if (!Active) return;
  168.    if (ISP >= IS + INCLUDE_MAX - 1) FATAL("Too many nested include files.");
  169.    if (ISP >= IS) {
  170.       ISP->Loc = ftell(InF);
  171.       if (ISP->Loc == -1L)
  172.          FATAL("Could not save %s's position.", FileTab[CurF]);
  173.       fclose(InF);
  174.       ISP->Next = Next, ISP->Line = Line, ISP->Path = CurF;
  175.    }
  176.    if (Files >= FileMax) {
  177.       FileMax += 4;
  178.       FileTab = (char **)realloc(FileTab, FileMax * sizeof *FileTab);
  179.       if (FileTab == 0) FATAL("Out of memory.");
  180.    }
  181.    ISP++, CurF = Files, FileTab[Files++] = CopyS(Name);
  182.    StartLine = Line = 1;
  183.    InF = fopen(Name, "r");
  184.    if (InF == 0) FATAL("Cannot open %s", Name);
  185.    Next = fgetc(InF);
  186. }
  187.  
  188. #define SEG_MAX 0x20
  189. struct Segment SegTab[SEG_MAX], *SegP;
  190. unsigned long LOC;
  191.  
  192. #define GAP_MAX 0x100
  193. struct Gap GapTab[GAP_MAX], *GapP;
  194.  
  195. struct AddrCard AddrTab[TYPES] = {
  196.    { 0, 0xffff, 1 },  /* CODE */
  197.    { 0, 0xffff, 0 },  /* XDATA */
  198.    { 0, 0xff, 0 },    /* DATA */
  199.    { 0x80, 0xff, 0 }, /* SFR */
  200.    { 0, 0xff, 0 }     /* BIT */
  201. };
  202. static struct AddrCard *AdP;
  203.  
  204. Symbol Sym;
  205.  
  206. static Symbol BTab[10], FTab[10];
  207. static Symbol MakeLabel(void) {
  208.    static unsigned long LAB = 0L; static char Buf[10];
  209.    sprintf(Buf, "#%x", LAB++);
  210.    return LookUp(Buf);
  211. }
  212.  
  213. void SegInit(void) {
  214.    int I, D;
  215.    for (SegP = SegTab, AdP = AddrTab, I = 0; I < TYPES; AdP++, I++, SegP++) {
  216.       if (SegP >= SegTab + SEG_MAX) FATAL("Too many segments.");
  217.       SegP->Type = I, SegP->Rel;
  218.       SegP->Base = 0, SegP->Size = 0, SegP->Loc = ftell(OutF);
  219.    }
  220.    AdP = AddrTab; InSeg = 1;
  221.    SegP->Type = 0, SegP->Rel = 1,
  222.    SegP->Line = StartLine, SegP->File = StartF,
  223.    SegP->Base = 0, SegP->Size = 0, SegP->Loc = ftell(OutF);
  224.    LOC = 0;
  225.    for (D = 0; D < 10; D++) BTab[0] = FTab[0] = 0;
  226.    GapP = GapTab;
  227. }
  228.  
  229. void StartSeg(byte Type, byte Rel, word Base) {
  230.    int D;
  231.    if (!Active) return;
  232.    if (SegP >= SegTab + SEG_MAX) FATAL("Too many segments.");
  233.    if (Type > sizeof AddrTab/sizeof *AddrTab)
  234.       FATAL("Undefined segment type.");
  235.    AdP = AddrTab + Type;
  236.    if (!Rel && (Base < AdP->Lo || Base > AdP->Hi))
  237.       FATAL("Address %u out of range", Base);
  238.    InSeg = 1;
  239.    SegP->Type = Type, SegP->Rel = Rel,
  240.    SegP->Line = StartLine, SegP->File = StartF,
  241.    SegP->Base = Base, SegP->Size = 0, SegP->Loc = ftell(OutF);
  242.    LOC = 0;
  243.    for (D = 0; D < 10; D++) BTab[0] = FTab[0] = 0;
  244. }
  245.  
  246. void EndSeg(void) {
  247.    int D;
  248.    if (!Active) return;
  249.    for (D = 0; D < 10; D++)
  250.       if (FTab[D] != 0) ERROR("Undefined label %d", D);
  251.    SegP->Size = (word)LOC;
  252.    if (SegP->Size > 0) SegP++;
  253.    InSeg = 0;
  254. }
  255.  
  256. void PByte(byte B) {
  257.    unsigned long Addr;
  258.    if (!Active) return;
  259.    if (!AdP->ReadOnly) FATAL("Attempting to write to a non-code segment.");
  260.    LOC++; Addr = SegP->Base + LOC;
  261.    if (!SegP->Rel && Addr > AdP->Hi + 1) FATAL("Address %u out of range", Addr);
  262.    fputc(B, OutF);
  263. }
  264.  
  265. void PString(char *S) {
  266.    if (!Active) return;
  267.    for (; *S != '\0'; S++) PByte(*S);
  268. }
  269.  
  270. void Space(word Rel) {
  271.    unsigned long Addr;
  272.    if (!Active) return;
  273.    if (AdP->ReadOnly) {
  274.       if (GapP >= GapTab + GAP_MAX) FATAL("Too many gaps.");
  275.       GapP->Seg = SegP, GapP->Offset = LOC, GapP->Size = Rel;
  276.       GapP++;
  277.    }
  278.    LOC += Rel;
  279.    Addr = SegP->Base + LOC;
  280.    if (!SegP->Rel && Addr > AdP->Hi + 1) FATAL("Address %u out of range", Addr);
  281. }
  282.  
  283. /* A hasty bug fix: accounts for the fact that the memory images stored in
  284.    files exclude gaps.
  285.  */
  286. long SegTell(Segment Seg, word Offset) {
  287.    long L = Seg->Loc + Offset; Gap G;
  288.    for (G = GapTab; G < GapP; G++)
  289.       if (G->Seg == Seg && G->Offset < Offset) L -= G->Size;
  290.    return L;
  291. }
  292.  
  293. static void Get(void) {
  294.    /* int Ch; */
  295.    if (Next == EOF) {
  296.       while (Next == EOF && ISP > IS) {
  297.          fclose(InF); ISP--;
  298.          Next = ISP->Next, Line = ISP->Line, CurF = ISP->Path;
  299.          InF = fopen(FileTab[CurF], "r");
  300.          if (InF == 0) FATAL("Cannot reopen %s", FileTab[CurF]);
  301.          if (fseek(InF, ISP->Loc, SEEK_SET) != 0) {
  302.             fclose(InF);
  303.             FATAL("Could not restore %s's position.", FileTab[CurF]);
  304.          }
  305.       }
  306.       if (Next == EOF) fclose(InF), Next = 0;
  307.       *U++ = ' ';
  308.    } else {
  309.       if (Next == '\n') Line++;
  310.       *U++ = Next; Next = fgetc(InF);
  311.    }
  312. }
  313.  
  314. typedef struct {
  315.    char *Name; Lexical Tag; int Value;
  316. } Card;
  317. static Card Reserved[] = {
  318.    { "ds", RB, 0 }, { "rb", RB, 0 }, { "rw", RW, 0 },
  319.    { "byte", DB, 0 }, { "word", DW, 0 }, { "db", DB, 0 }, { "dw", DW, 0 },
  320.    { "seg", SEG, 0 }, { "end", END, 0 },
  321.    { "org", ORG, 0 }, { "at", ORG, 0 }, { "equ", EQU, 0 }, { "set", SET, 0 },
  322.    { "include", INCLUDE, 0 }, { "global", GLOBAL, 0 }, { "public", GLOBAL, 0 },
  323.    { "extern", EXTERN, 0 }, { "if", IF, 0 }, { "else", ELSE, 0 },
  324.    { "high", HIGH, 0 }, { "low", LOW, 0 }, { "by", BY, 0 },
  325.    { "code", TYPE, CODE }, { "xdata", TYPE, XDATA },
  326.    { "bit", TYPE, BIT }, { "sfr", TYPE, SFR }, { "data", TYPE, DATA },
  327.    { "a", REGISTER, ACC }, { "ab", REGISTER, AB }, { "c", REGISTER, CY },
  328.    { "dptr", REGISTER, DPTR }, { "pc", REGISTER, PC },
  329.    { "r0", REGISTER, R0 }, { "r1", REGISTER, R1 },
  330.    { "r2", REGISTER, R2 }, { "r3", REGISTER, R3 },
  331.    { "r4", REGISTER, R4 }, { "r5", REGISTER, R5 },
  332.    { "r6", REGISTER, R6 }, { "r7", REGISTER, R7 }
  333. };
  334.  
  335. #define ELEMENTS(Arr) (sizeof(Arr)/sizeof(Arr[0]))
  336.  
  337. static Lexical FindKey(char *Name) {
  338.    Code *CP; Card *C;
  339.    static Card *EndR = Reserved + ELEMENTS(Reserved);
  340.    for (CP = CodeTab; CP->Name != 0; CP++)
  341.       if (CompS(Name, CP->Name) == 0) {
  342.          Value = CP - CodeTab; return MNEMONIC;
  343.       }
  344.    for (C = Reserved; C < EndR; C++)
  345.       if (CompS(Name, C->Name) == 0) {
  346.          Value = C->Value; return C->Tag;
  347.       }
  348.    Sym = LookUp(Name);
  349.    return SYMBOL;
  350. }
  351.  
  352. typedef struct {
  353.    char *Name; byte Type; word Val;
  354. } ValCard;
  355. static ValCard ValTab[] = {
  356. /* Special function registers */
  357.    { "P0", SFR, 0x80 }, { "P1", SFR, 0x90 },
  358.    { "P2", SFR, 0xa0 }, { "P3", SFR, 0xb0 },
  359.    { "PCON", SFR, 0x87 }, { "TCON", SFR, 0x88 }, { "TMOD", SFR, 0x89 },
  360.    { "SCON", SFR, 0x98 }, { "SBUF", SFR, 0x99 },
  361.    { "IE",   SFR, 0xa8 }, { "IP",   SFR, 0xb8 },
  362.    { "TL0", SFR, 0x8a }, { "TL1", SFR, 0x8b },
  363.    { "TH0", SFR, 0x8c }, { "TH1", SFR, 0x8d },
  364.    { "SP",   SFR, 0x81 }, { "DPL",  SFR, 0x82 }, { "DPH",  SFR, 0x83 },
  365.    { "PSW",  SFR, 0xd0 }, { "ACC",  SFR, 0xe0 }, { "B",    SFR, 0xf0 },
  366. /* Special funcgtion register bits */
  367.    { "RI",  BIT, 0x98 }, { "TI",  BIT, 0x99 },    /* SCON */
  368.    { "RB8", BIT, 0x9a }, { "TB8", BIT, 0x9b },
  369.    { "REN", BIT, 0x9c }, { "SM2", BIT, 0x9d },
  370.    { "SM1", BIT, 0x9e }, { "SM0", BIT, 0x9f },
  371.    { "RXD",  BIT, 0xb0 }, { "TXD",  BIT, 0xb1 },  /* Port 3 */
  372.    { "INT0", BIT, 0xb2 }, { "INT1", BIT, 0xb3 },
  373.    { "T0",   BIT, 0xb4 }, { "T1",   BIT, 0xb5 },
  374.    { "WR",   BIT, 0xb6 }, { "RD",   BIT, 0xb7 },
  375.    { "P",   BIT, 0xd0 }, { "OV",  BIT, 0xd2 },    /* PSW */
  376.    { "RS0", BIT, 0xd3 }, { "RS1", BIT, 0xd4 },
  377.    { "F0",  BIT, 0xd5 }, { "AC",  BIT, 0xd6 }, { "CY",  BIT, 0xd7 },
  378.    { "IT0", BIT, 0x88 }, { "IE0", BIT, 0x89 },    /* TCON */
  379.    { "IT1", BIT, 0x8a }, { "IE1", BIT, 0x8b },
  380.    { "TR0", BIT, 0x8c }, { "TF0", BIT, 0x8d },
  381.    { "TR1", BIT, 0x8e }, { "TF1", BIT, 0x8f },
  382.    { "EX0", BIT, 0xa8 }, { "ET0", BIT, 0xa9 },    /* IE */
  383.    { "EX1", BIT, 0xaa }, { "ET1", BIT, 0xab },
  384.    { "ES",  BIT, 0xac }, { "EA",  BIT, 0xaf },
  385.    { "PX0", BIT, 0xb8 }, { "PT0", BIT, 0xb9 },    /* IP */
  386.    { "PX1", BIT, 0xba }, { "PT1", BIT, 0xbb }, { "PS",  BIT, 0xbc }
  387. };
  388.  
  389. void RegInit(void) {
  390.    ValCard *V; Symbol Sym;
  391.    static ValCard *EndV = ValTab + ELEMENTS(ValTab);
  392.    for (V = ValTab; V < EndV; V++) {
  393.       Sym = LookUp(V->Name);
  394.       Sym->Defined = Sym->Address = 1;
  395.       Sym->Seg = &SegTab[V->Type], Sym->Offset = V->Val;
  396.    }
  397. }
  398.  
  399. #define isoctal(Ch) (isdigit(Ch) && Ch < '8')
  400. #define isx(Ch) (tolower(Ch) == 'x' || tolower(Ch) == 'h')
  401. #define isq(Ch) (tolower(Ch) == 'q' || tolower(Ch) == 'o')
  402.  
  403. char InExp = 0, InSemi = 0;
  404. Lexical OldL;
  405. #define Ret(Token) return (*U = '\0', OldL = (Token))
  406.  
  407. Lexical Scan(void) {
  408.    char *S; int Bad;
  409. Start:
  410.    U = Text;
  411.    if (isalpha(Next) || Next == '_') {
  412.       while (isalnum(Next) || Next == '_') Get();
  413.       Ret(FindKey(Text));
  414.    } else if (isdigit(Next)) {
  415.       char Ch = Next; Get();
  416.       if (Ch == '0' && isx(Next)) {
  417.          do Get(); while (isxdigit(Next));
  418.          goto RetHex;
  419.       }
  420.       if (Next == ':' && !InExp) {
  421.          char D = *Text - '0';
  422.          if (Active) {
  423.             Sym = BTab[D] = (FTab[D] == 0)? MakeLabel(): FTab[D];
  424.             FTab[D] = 0;
  425.             Sym->Global = 0, Sym->Defined = Sym->Address = Sym->Variable = 1,
  426.             Sym->Seg = SegP, Sym->Offset = (word)LOC;
  427.          } else Sym = 0;
  428.          Ret(SYMBOL);
  429.       }
  430.       while (isxdigit(Next)) Get();
  431.       if (isx(Next)) { Get(); goto RetHex; }
  432.       if (isq(Next)) { Get(); goto RetOct; }
  433.       if (U - Text == 2) {
  434.          if (tolower(Text[1]) == 'b') {
  435.             char D = *Text - '0';
  436.             if (Active) {
  437.                Sym = BTab[D];
  438.                if (Sym == 0) {
  439.                   BTab[D] = Sym = MakeLabel();
  440.                   ERROR("Undefined local symbol %cb", D);
  441.                   Sym->Global = Sym->Defined = 0,
  442.                   Sym->Address = Sym->Variable = 1,
  443.                   Sym->Seg = SegP, Sym->Offset = 0;
  444.                }
  445.             } else Sym = 0;
  446.             Ret(SYMBOL);
  447.          } else if (tolower(Text[1]) == 'f') {
  448.             char D = *Text - '0';
  449.             if (Active) {
  450.                if (FTab[D] == 0) FTab[D] = MakeLabel();
  451.                Sym = FTab[D];
  452.             } else Sym = 0;
  453.             Ret(SYMBOL);
  454.          }
  455.       }
  456.       if (tolower(U[-1]) == 'b') goto RetBin;
  457.       if (tolower(U[-1]) == 'd' || *Text != '0') goto RetDec;
  458.       if (U == Text) { Value = 0; Ret(NUMBER); }
  459.       if (isx(Text[1])) goto RetHex;
  460.       if (tolower(Text[1]) == 'b') goto RetBin;
  461.       goto RetDec;
  462. RetBin:
  463.       S = Text;
  464.       if (tolower(U[-1]) == 'b') U--;
  465.       else if (U >= S + 2 && S[0] == '0' && tolower(S[1]) == 'b') S += 2;
  466.       for (Bad = 0, Value = 0; S < U; S++) {
  467.          int D = *S - '0';
  468.          if (!isdigit(*S) || D >= 2) Bad++, D = 0;
  469.          Value = (Value << 1) | D;
  470.       }
  471.       if (Bad) ERROR("Binary number has non-binary digits.");
  472.       Ret(NUMBER);
  473. RetOct:
  474.       if (isq(U[-1])) U--;
  475.       for (Bad = 0, Value = 0, S = Text; S < U; S++) {
  476.          int D = *S - '0';
  477.          if (!isdigit(*S) || D >= 010) Bad++, D = 0;
  478.          Value = (Value << 3) | D;
  479.       }
  480.       if (Bad) ERROR("Octal number has non-octal digits.");
  481.       Ret(NUMBER);
  482. RetDec:
  483.       if (tolower(U[-1]) == 'd') U--;
  484.       for (Bad = 0, Value = 0, S = Text; S < U; S++) {
  485.          int D = *S - '0';
  486.          if (!isdigit(*S)) Bad++, D = 0;
  487.          Value = 10*Value + D;
  488.       }
  489.       if (Bad) ERROR("Decimal number has non-decimal digits.");
  490.       Ret(NUMBER);
  491. RetHex:
  492.       S = Text;
  493.       if (isx(U[-1])) U--;
  494.       else if (U >= S + 2 && S[0] == '0' && isx(S[1])) S += 2;
  495.       for (Value = 0; S < U; S++) {
  496.          Value <<= 4, Value += isdigit(*S)? *S - '0': tolower(*S) - 'a' + 10;
  497.       }
  498.       Ret(NUMBER);
  499.    }
  500.    switch (Next) {
  501.       case ';': switch (Get(), Next) {
  502.          case ';':
  503.             while (Next != '\n') {
  504.                if (Next == EOF) FATAL("Unexpected EOF inside ;; comment.");
  505.                Next = fgetc(InF);
  506.             }
  507.             Get();
  508.             if (!InSemi) goto Start;
  509.          default: Ret(SEMI);
  510.       }
  511.       break;
  512.       case '/': switch (Get(), Next) {
  513.          case '/':
  514.             while (Next != '\n') {
  515.                if (Next == EOF) FATAL("Unexpected EOF inside // comment.");
  516.                Next = fgetc(InF);
  517.             }
  518.             Get();
  519.             if (!InSemi) goto Start;
  520.          Ret(SEMI);
  521.          case '*': {
  522.             int Line0 = Line;
  523.             Next = fgetc(InF);
  524.             while (Next != EOF) {
  525.                if (Next == '*') {
  526.                   while (Next == '*') Next = fgetc(InF);
  527.                   if (Next == '/') {
  528.                      Next = fgetc(InF);
  529.                      if (Line <= Line0 || !InSemi) goto Start;
  530.                      Ret(SEMI);
  531.                   }
  532.                } else {
  533.                   if (Next == '\n') Line++; Next = fgetc(InF);
  534.                }
  535.             }
  536.             FATAL("Unexpected EOF inside comment.");
  537.          }
  538.          default: Ret(DIV);
  539.       }
  540.       case '\'':
  541.      Get();
  542.          if (Next == '\'') {
  543.             ERROR("Empty character constant."); Get(); Value = 0; Ret(NUMBER);
  544.          }
  545.      if (Next == '\\') {
  546.             int I;
  547.         Get();
  548.         if (isoctal(Next)) {
  549.            for (Value = 0; isoctal(Next); Get())
  550.                   Value <<= 3, Value += Next - '0';
  551.         } else if (tolower(Next) == 'x') {
  552.            Get();
  553.                if (!isxdigit(Next)) {
  554.                   ERROR("Bad hexadecimal character.");
  555.                   Value = 'x';
  556.                } else for (I = 0; I < 2 && isxdigit(Next); I++, Get()) {
  557.                   Value <<= 4;
  558.                   Value += isdigit(Next)? Next - '0': tolower(Next) - 'a' + 10;
  559.                }
  560.         } else {
  561.                switch (Next) {
  562.                   case 'a': Value = 0x07; break;
  563.                   case 'b': Value = 0x08; break;
  564.                   case 't': Value = 0x09; break;
  565.                   case 'n': Value = 0x0a; break;
  566.                   case 'v': Value = 0x0b; break;
  567.                   case 'f': Value = 0x0c; break;
  568.                   case 'r': Value = 0x0d; break;
  569.                   default: Value = Next; break;
  570.                }
  571.                Get();
  572.             }
  573.      } else Value = Next, Get();
  574.      if (Next != '\'') ERROR("Missing a ' in character constant.");
  575.          else Get();
  576.       Ret(NUMBER);
  577.       case '"':
  578.          Next = fgetc(InF);
  579.          while (Next != '\"') {
  580.             if (Next == EOF) FATAL("Unexpected EOF inside string.");
  581.             else if (Next == '\\') {
  582.                Next = fgetc(InF);
  583.                if (Next == EOF) FATAL("Unexpected EOF inside string.");
  584.            if (isoctal(Next)) {
  585.                   char Value = 0;
  586.                   while (isoctal(Next)) {
  587.                      Value = (Value << 3) + (Next - '0');
  588.                      Next = fgetc(InF);
  589.                   }
  590.                   *U++ = Value;
  591.            } else if (tolower(Next) == 'x') {
  592.                   char Value;
  593.                   Next = fgetc(InF);
  594.                   if (!isxdigit(Next)) Value = 'x';
  595.           else while (isxdigit(Next)) {
  596.                      Value <<= 4;
  597.                      Value += isdigit(Next)? Next - '0': tolower(Next) - 'a' + 10;
  598.                      Next = fgetc(InF);
  599.                   }
  600.                   *U++ = Value;
  601.            } else {
  602.                   if (Next == '\n') Line++;
  603.                   switch (Next) {
  604.                      case 'a': *U++ = '\a'; break;
  605.                      case 'b': *U++ = '\b'; break;
  606.                      case 't': *U++ = '\t'; break;
  607.                      case 'n': *U++ = '\n'; break;
  608.                      case 'v': *U++ = '\v'; break;
  609.                      case 'f': *U++ = '\f'; break;
  610.                      case 'r': *U++ = '\r'; break;
  611.                      default: *U++ = Next; break;
  612.                   }
  613.                   Next = fgetc(InF);
  614.                }
  615.         } else {
  616.                if (Next == '\n') Line++;
  617.                *U++ = Next; Next = fgetc(InF);
  618.             }
  619.          }
  620.          Next = fgetc(InF);
  621.       Ret(STRING);
  622.       case '<': switch (Get(), Next) {
  623.      case '=': Get(); Ret(LE);
  624.      case '<': Get(); Ret(SHL);
  625.          default: Ret(LT);
  626.       }
  627.       case '>': switch (Get(), Next) {
  628.      case '=': Get(); Ret(GE);
  629.      case '>': Get(); Ret(SHR);
  630.      default: Ret(GT);
  631.       }
  632.       case '&': switch (Get(), Next) {
  633.      case '&': Get(); Ret(AND_AND);
  634.      default: Ret(AND);
  635.       }
  636.       case '|': switch (Get(), Next) {
  637.      case '|': Get(); Ret(OR_OR);
  638.      default: Ret(OR);
  639.       }
  640.       case '=': switch (Get(), Next) {
  641.      case '=': Get(); Ret(EQ);
  642.      default: Ret(SET);
  643.       }
  644.       case '!': switch (Get(), Next) {
  645.      case '=': Get(); Ret(NE);
  646.      default: Ret(NOT_NOT);
  647.       }
  648.       case '\n': Get(); if (!InSemi) goto Start; Ret(SEMI);
  649.       case '^': Get(); Ret(XOR);
  650.       case '+': Get(); Ret(PLUS);
  651.       case '-': Get(); Ret(MINUS);
  652.       case '*': Get(); Ret(MULT);
  653.       case '%': Get(); Ret(MOD);
  654.       case '@': Get(); Ret(AT);
  655.       case '#': Get(); Ret(POUND);
  656.       case '$': Get(); Ret(DOLLAR);
  657.       case '.': Get(); Ret(DOT);
  658.       case '~': Get(); Ret(NOT);
  659.       case ',': Get(); Ret(COMMA);
  660.       case ':': Get(); Ret(COLON);
  661.       case '?': Get(); Ret(QUEST);
  662.       case '{': Get(); Ret(LCURL);
  663.       case '}': Get(); Ret(RCURL);
  664.       case '(': Get(); Ret(LPAR);
  665.       case ')': Get(); Ret(RPAR);
  666.       case 0: Ret(0);
  667.       default: Get(); goto Start;
  668.    }
  669. }
  670.  
  671.